"""
UI自动化脚本执行器服务
集成Midscene等UI自动化框架
"""

import json
import yaml
import asyncio
import subprocess
import tempfile
import os
from typing import Dict, Any, List
from datetime import datetime
from sqlalchemy.orm import Session
from ..models.ui_automation import UiTaskResult, UiStepResult, ExecutionStatus


class UiExecutorService:
    """UI自动化脚本执行器"""

    def __init__(self, db: Session):
        self.db = db

    async def execute_yaml_script(self, task_id: int, yaml_content: str) -> bool:
        """
        执行YAML脚本
        """
        try:
            # 解析YAML内容
            parsed_yaml = yaml.safe_load(yaml_content)
            tasks = parsed_yaml.get("tasks", [])

            for task_index, task in enumerate(tasks):
                task_name = task.get("name", f"任务{task_index + 1}")
                continue_on_error = task.get("continueOnError", False)
                flow_steps = task.get("flow", [])

                # 创建任务结果记录
                task_result = UiTaskResult(
                    execution_id=task_id,
                    task_name=task_name,
                    task_index=task_index,
                    status=ExecutionStatus.RUNNING,
                    start_time=datetime.now(),
                    step_count=len(flow_steps)
                )
                self.db.add(task_result)
                self.db.commit()
                self.db.refresh(task_result)

                try:
                    # 执行任务中的步骤
                    success_steps, failed_steps = await self._execute_task_steps(
                        task_result.id, flow_steps
                    )

                    # 更新任务结果
                    task_result.status = ExecutionStatus.SUCCESS if failed_steps == 0 else ExecutionStatus.FAILED
                    task_result.end_time = datetime.now()
                    task_result.duration = int(
                        (task_result.end_time - task_result.start_time).total_seconds() * 1000
                    )
                    task_result.success_steps = success_steps
                    task_result.failed_steps = failed_steps

                except Exception as e:
                    task_result.status = ExecutionStatus.FAILED
                    task_result.end_time = datetime.now()
                    task_result.duration = int(
                        (task_result.end_time - task_result.start_time).total_seconds() * 1000
                    )
                    task_result.error_message = str(e)

                    if not continue_on_error:
                        self.db.commit()
                        return False

                self.db.commit()

            return True

        except Exception as e:
            raise Exception(f"执行YAML脚本失败: {str(e)}")

    async def _execute_task_steps(self, task_id: int, flow_steps: List[Dict[str, Any]]) -> tuple:
        """
        执行任务中的步骤
        返回 (成功步骤数, 失败步骤数)
        """
        success_count = 0
        failed_count = 0

        for step_index, step in enumerate(flow_steps):
            step_result = UiStepResult(
                task_id=task_id,
                step_index=step_index,
                step_type=self._get_step_type(step),
                step_content=json.dumps(step, ensure_ascii=False),
                status=ExecutionStatus.RUNNING,
                start_time=datetime.now()
            )
            self.db.add(step_result)
            self.db.commit()
            self.db.refresh(step_result)

            try:
                # 执行具体步骤
                await self._execute_single_step(step, step_result)
                
                step_result.status = ExecutionStatus.SUCCESS
                success_count += 1

            except Exception as e:
                step_result.status = ExecutionStatus.FAILED
                step_result.error_message = str(e)
                failed_count += 1

            finally:
                step_result.end_time = datetime.now()
                step_result.duration = int(
                    (step_result.end_time - step_result.start_time).total_seconds() * 1000
                )
                self.db.commit()

        return success_count, failed_count

    async def _execute_single_step(self, step: Dict[str, Any], step_result: UiStepResult):
        """
        执行单个步骤
        """
        step_type = self._get_step_type(step)

        # 根据步骤类型执行不同的操作
        if step_type in ["ai", "aiAction"]:
            await self._execute_ai_action(step, step_result)
        elif step_type == "aiTap":
            await self._execute_ai_tap(step, step_result)
        elif step_type == "aiHover":
            await self._execute_ai_hover(step, step_result)
        elif step_type == "aiInput":
            await self._execute_ai_input(step, step_result)
        elif step_type == "aiKeyboardPress":
            await self._execute_ai_keyboard_press(step, step_result)
        elif step_type == "aiScroll":
            await self._execute_ai_scroll(step, step_result)
        elif step_type == "aiAssert":
            await self._execute_ai_assert(step, step_result)
        elif step_type == "aiWaitFor":
            await self._execute_ai_wait_for(step, step_result)
        elif step_type == "aiQuery":
            await self._execute_ai_query(step, step_result)
        elif step_type == "logScreenshot":
            await self._execute_log_screenshot(step, step_result)
        elif step_type == "sleep":
            await self._execute_sleep(step, step_result)
        elif step_type == "javascript":
            await self._execute_javascript(step, step_result)
        else:
            raise Exception(f"不支持的步骤类型: {step_type}")

    def _get_step_type(self, step: Dict[str, Any]) -> str:
        """获取步骤类型"""
        for key in step.keys():
            if key in ["ai", "aiAction", "aiTap", "aiHover", "aiInput", "aiKeyboardPress", 
                      "aiScroll", "aiAssert", "aiWaitFor", "aiQuery", "logScreenshot", 
                      "sleep", "javascript"]:
                return key
        return "unknown"

    async def _execute_ai_action(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行AI动作"""
        prompt = step.get("ai") or step.get("aiAction")
        # 这里可以集成实际的AI执行逻辑
        await asyncio.sleep(1)  # 模拟执行时间
        print(f"执行AI动作: {prompt}")

    async def _execute_ai_tap(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行点击操作"""
        locate = step.get("aiTap")
        xpath = step.get("xpath")
        deep_think = step.get("deepThink", False)
        
        # 这里可以集成Midscene或其他UI自动化框架
        await asyncio.sleep(0.5)  # 模拟执行时间
        print(f"点击元素: {locate}")

    async def _execute_ai_hover(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行悬停操作"""
        locate = step.get("aiHover")
        await asyncio.sleep(0.3)  # 模拟执行时间
        print(f"悬停元素: {locate}")

    async def _execute_ai_input(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行输入操作"""
        value = step.get("aiInput")
        locate = step.get("locate")
        await asyncio.sleep(0.5)  # 模拟执行时间
        print(f"输入文本 '{value}' 到 '{locate}'")

    async def _execute_ai_keyboard_press(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行按键操作"""
        key = step.get("aiKeyboardPress")
        locate = step.get("locate")
        await asyncio.sleep(0.2)  # 模拟执行时间
        print(f"按下按键 '{key}' 在 '{locate}'")

    async def _execute_ai_scroll(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行滚动操作"""
        scroll_config = step.get("aiScroll", {})
        direction = scroll_config.get("direction", "down")
        scroll_type = scroll_config.get("scrollType", "once")
        await asyncio.sleep(0.3)  # 模拟执行时间
        print(f"滚动 {direction} - {scroll_type}")

    async def _execute_ai_assert(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行断言"""
        assertion = step.get("aiAssert")
        error_message = step.get("errorMessage")
        await asyncio.sleep(0.5)  # 模拟执行时间
        print(f"断言: {assertion}")
        # 这里应该实际验证页面状态

    async def _execute_ai_wait_for(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行等待操作"""
        condition = step.get("aiWaitFor")
        timeout = step.get("timeout", 30000) / 1000  # 转换为秒
        await asyncio.sleep(min(1, timeout / 10))  # 模拟等待时间
        print(f"等待条件: {condition}")

    async def _execute_ai_query(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行数据查询"""
        query = step.get("aiQuery")
        name = step.get("name")
        await asyncio.sleep(0.5)  # 模拟执行时间
        print(f"查询数据: {query}")
        
        # 模拟查询结果
        result_data = {"query_result": "模拟数据"}
        step_result.result_data = json.dumps(result_data, ensure_ascii=False)

    async def _execute_log_screenshot(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行截图"""
        title = step.get("logScreenshot", "screenshot")
        content = step.get("content", "")
        await asyncio.sleep(0.2)  # 模拟执行时间
        print(f"截图: {title}")
        
        # 这里应该实际截图并保存
        screenshot_url = f"/screenshots/{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
        step_result.screenshot_url = screenshot_url

    async def _execute_sleep(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行等待"""
        duration = step.get("sleep", 1000) / 1000  # 转换为秒
        await asyncio.sleep(min(duration, 5))  # 最多等待5秒
        print(f"等待 {duration} 秒")

    async def _execute_javascript(self, step: Dict[str, Any], step_result: UiStepResult):
        """执行JavaScript"""
        js_code = step.get("javascript")
        name = step.get("name")
        await asyncio.sleep(0.2)  # 模拟执行时间
        print(f"执行JavaScript: {js_code}")
        
        # 模拟JavaScript执行结果
        if name:
            result_data = {"js_result": "执行成功"}
            step_result.result_data = json.dumps(result_data, ensure_ascii=False)

    async def execute_with_midscene(self, yaml_content: str) -> Dict[str, Any]:
        """
        使用Midscene执行UI自动化脚本
        这是一个示例方法，展示如何集成实际的UI自动化框架
        """
        try:
            # 创建临时脚本文件
            with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
                f.write(yaml_content)
                script_path = f.name

            # 创建Midscene执行脚本
            midscene_script = f"""
const {{ test }} = require('@midscene/core');
const fs = require('fs');
const yaml = require('js-yaml');

async function runTest() {{
    try {{
        const yamlContent = fs.readFileSync('{script_path}', 'utf8');
        const config = yaml.load(yamlContent);
        
        // 这里应该是实际的Midscene执行逻辑
        console.log('执行UI自动化脚本...');
        
        return {{
            success: true,
            message: '执行成功',
            results: []
        }};
    }} catch (error) {{
        return {{
            success: false,
            message: error.message,
            error: error.stack
        }};
    }}
}}

runTest().then(result => {{
    console.log(JSON.stringify(result));
}});
"""

            # 创建Node.js脚本文件
            with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False) as f:
                f.write(midscene_script)
                js_script_path = f.name

            # 执行Node.js脚本
            process = await asyncio.create_subprocess_exec(
                'node', js_script_path,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE
            )

            stdout, stderr = await process.communicate()

            # 清理临时文件
            os.unlink(script_path)
            os.unlink(js_script_path)

            if process.returncode == 0:
                try:
                    result = json.loads(stdout.decode())
                    return result
                except json.JSONDecodeError:
                    return {
                        "success": False,
                        "message": "解析执行结果失败",
                        "output": stdout.decode()
                    }
            else:
                return {
                    "success": False,
                    "message": "脚本执行失败",
                    "error": stderr.decode()
                }

        except Exception as e:
            return {
                "success": False,
                "message": f"执行脚本失败: {str(e)}"
            }
